/*
    TreeViewer - Cross-platform software to draw phylogenetic trees
    Copyright (C) 2023  Giorgio Bianchini, University of Bristol
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, version 3.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using PhyloTree;
using TreeViewer;
using VectSharp;

namespace PruneSelection
{
    /// <summary>
    /// <![CDATA[
    /// This module is used to apply the _Polytomise node_ Further transformation to the selected node.
    /// 
    /// **Note**: using this module without installing also the _Polytomise node_ module (id `19d9a555-07e6-4dac-afc1-d5ffcef35f76`) may lead
    /// to program crashes or unexpected results.
    /// 
    /// ## Further information
    /// 
    /// This module can be used to polytomise the selected node, its direct descendants, all of the descendants, or both the selected node and
    /// all of its descendants.
    /// 
    /// To understand the difference between these options, consider the following tree:
    /// 
    /// <p align="center">
    ///     <img height="400" src=""/>
    /// </p>
    ///
    /// Assume that the currently selected node is `3` (the branch in blue). If the only selected node is polytomised, the result is that branch
    /// `3` disappears from the tree:
    ///
    /// <p align="center">
    ///     <img height="400" src="" />
    /// </p>
    ///
    /// If the direct descendants of the selected node are polytomised, branch `2` (green) disappears instead:
    ///
    /// <p align="center">
    ///     <img height="400" src="" />
    /// </p>
    ///
    /// If all the descendants of the selected node are polytomised, branches `1` (orange) and `2` (green) both disappear:
    /// 
    /// <p align="center">
    ///     <img height="400" src="" />
    /// </p>
    ///
    /// Finally, if both the node and its descendants are polytomised, all three coloured branches disappear:
    /// 
    /// <p align="center">
    ///     <img height="400" src="" />
    /// </p>
    ///
    /// The default action (i.e. the action performed when the user clicks on the button without explicitly choosing which node to polytomise)
    /// depends on the selected node:
    /// 
    /// * The action cannot be applied to a leaf node.
    /// * If the selected node is a subterminal node (i.e. its children are all leaves), then the selected node is polytomised.
    /// * If the selected node is an internal node (i.e. not all of its children are leaves) or the root node of the tree, then all the descendants
    /// of the selected node are polytomised.
    /// 
    /// ]]>
    /// </summary>

    public static class MyModule
    {
        public const string Name = "Polytomise selection";
        public const string HelpText = "Transforms the selected node into a polytomy.";
        public const string Author = "Giorgio Bianchini";
        public static Version Version = new Version("1.1.2");
        public const string Id = "8202afa4-c9a6-47ac-98d5-dd0190c23f63";
        public const ModuleTypes ModuleType = ModuleTypes.SelectionAction;
        public static bool IsAvailableInCommandLine { get; } = true;

        public static string ButtonText { get; } = "Create polytomy";
        public static Avalonia.Input.Key ShortcutKey { get; } = Avalonia.Input.Key.None;
        public static Avalonia.Input.KeyModifiers ShortcutModifier { get; } = Avalonia.Input.KeyModifiers.None;
        public static bool TriggerInTextBox { get; } = false;

        public static string GroupName { get; } = "Simplify";
        public static double GroupIndex { get; } = 2;
        public static bool IsLargeButton { get; } = false;
        public static List<(string, Func<double, Page>)> SubItems { get; } = new List<(string, Func<double, Page>)>()
        {
            ( "", null ),
            ( "Polytomise selected node", scaling => GetIcon(scaling, Icon_0_16, Icon_0_24,Icon_0_32)),
            ( "Polytomise direct descendants", scaling => GetIcon(scaling, Icon_1_16, Icon_1_24,Icon_1_32) ),
            ( "Polytomise all descendants", scaling => GetIcon(scaling, Icon_2_16, Icon_2_24,Icon_2_32) ),
            ( "Polytomise node and all descendants", scaling => GetIcon(scaling, Icon_3_16, Icon_3_24,Icon_3_32) )
        };

        private static string Icon16Base64 = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABqSURBVDhPY6AUMEJpOCgqKvoPZZIHSDWACUqTDSg2ACMMkAEx3kExwKt2YwOQqgfixm3N/iA2QcAEsgWEgQDEB2lGpgkCpr6+PkYQBgIQvxEsiqAJAowwALkEahh5aWIYpAOy/D2AgIEBAK9sIxBWstekAAAAAElFTkSuQmCC";
        private static string Icon24Base64 = "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADESURBVEhLzZRNDgIhDIWLJxu3mngYWPu75zBO4lpvhpRpDAMMKGUiXzIpkAmPtg+EMQbWRFBchHuARQEp5cWG8zSrZ0MxBXtzJJeBq43W+vOPEMWKRuQyaEJfAuioX79iD7gkBVDZRylVbVl3k0N37I73wYbnNIPt43Z44aDGRSIsBdpyfxpna1bA7dylTZNHaloiihF+o1lNphixqk2Rv7xF4f34hr7eoqYuatXkKAOsM9X66haYFHOuaaxPVoC7OQDAG55GbedfodH5AAAAAElFTkSuQmCC";
        private static string Icon32Base64 = "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAERSURBVFhH7ZZLDoIwEIapJ3Otid4F1j7QNYfRRLceDTuFmkltO1Po2JD4JZNSQunfeYGqPPR9P17J4xWAkRZDCqjr+qyH0zDLz2ocY4htDnA8YGLQdZ3SmHtcOOHjeGAWIDpmogJgAwpxD1D8BSQJgKzObewylIIUACotTdOs9fAaZnmICtgcbrgNt8/rHuZerFBO6eFnFT4hZnu8+74BHxGhdT5go9DzyhdjaLtagHfF47Kjj5hA8TL8Oo11VSgE2gPBPJjCpCQEkTbZrOBYnGOQ8cQv/XkZAsUbEf4hMTcyk1QFpnE4loq7fnYZui+kzGVZn2MJli8A+kTMKIr3AY4H2nEUgfQAx41zKJyEVfUGjAG3F+nFSsIAAAAASUVORK5CYII=";

        private static string Icon_0_16 = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAC3SURBVDhPnZJhDsIgDIXB7HYmHgb+O+d/OIyJ50Me4xFgZaJf0rSD9tEytJoghJCjHWttuyCBopEZY6LbNYYdMAFIJzrnjrU8oTeeKH1fcm2D1t+vBl3BmkwogumWe9jWWcu9iSP8wgKV6/31iPEa/fZ+3hAfGP37Jfu18kkAFwlx4L0X569H2DpfigFiycom4Ub90nqYQ9NIZossGs0rAoEcFvpTKAzqGEy/xFqIMSyNkFb/QqkPWqrxaDSOh+cAAAAASUVORK5CYII=";
        private static string Icon_1_16 = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAC4SURBVDhPjZJhDsIgDIWpx5uJh4HfU+d/uIsmng95jJKCZeNLXihsPNoCmQlijCXacc61CxrYNJK1Ng27xzAD/gFoJ3rv//fyCWfiDKDGBQuAiMyyvp8pfCRt39cNcUVmpBqA6/1TJ8lgWOqljBpbN6oMM5iFtE2oUXb56N4JHS1xQwihmqOpGvm7NMACJK/pTEdNzCf36sklIF1M4Aim3jqj9aBPk42BjIFagpaqNOIYGt7CHMb8AOtszOmV3Ad3AAAAAElFTkSuQmCC";
        private static string Icon_2_16 = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAC5SURBVDhPjZLdDsIgDIWpj6eJDwPXU+c9vIsmez7kEItdV5AvaSglPf3ZyE2Qc/56P0IINdgV0EmX2/tRjnuxdXte4Tsicic4kyBZnrXITgABNoNVnZXdCJyI1s7L69CyxNyBrFxmbpci0N3VaAdmy5puB7OQlYT5YoxNnOe1IO+9+ZhSauJYqkV9lwIIwBBj/58NfyRU1qapI6BdXKAIRjMfsHag22RhIH1gjmC1KoXYh3W/whzOfQCHF5t2Nt7DwwAAAABJRU5ErkJggg==";
        private static string Icon_3_16 = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADGSURBVDhPnZJdDgIhDITBeDpNPAz77M/6DnfRxPMhQxjsQtkQv6RpF2jplLVmghhjiX4sy5IXhwXapPPt/Ujunmz9PC+IjbXWHBBMgmTp8yWbAligKayNz2wkMBGtna6vrmWJOgN5c9JcP1KB4az2ZqC23DLsYBaLpPaJoM97X4tTr8axePlE9Y3ZUQhBnQH2OYNOr5SDWLO6SbjhnEtO75pnaBaH2SKT9jR3oEAJK+0tLAxkDNT/AANskYUYw7KEvPoXxnwBP7WnNz1vvD4AAAAASUVORK5CYII=";

        private static string Icon_0_24 = "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEKSURBVEhLtZVLDsIgEIah8WB2beJh2r2vPT2MiWu9WeXHGaV0qEDgSwiUknn8M7RaVWIYhoudzp+nHx3NNVgZB9kZzPNMqyXjOLoX0zQtbGY5gHFrSJSC8R3gfIlEUeMhWuuiDEQpbJFF7aIZwFg4/nCleYGYAYzlaB0DdrZqkKx1DNRg5SCUApFiGGPcoO1ktjIQNc1Fc8SH031vp6d7UKp/3I4vdAxrzee4i1LpqJiAjQN/7YCeRFZmOztQTHayCTnB2aTzYRf1NAN/XYwLCDeQPrVf4Bl7sduZip+B1PNuj4tbiuYo/ZsJo7ndEqP5PeAaVIk2JOyiJjR14H44reRhkEGdYooo9QbItYM5KaQiCgAAAABJRU5ErkJggg==";
        private static string Icon_1_24 = "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAD+SURBVEhLtZVhEoIgEIWlk9nfuo38ruwAcpe6IPFoKVxXBMRvZgdFZx+7D1R1jRiGYXTD43v350RjCxbJQXEF1lq6mqO19g+MMbOcRQJI7hKJrQjEAni/pkWryTlKqfoKeCucyWLvVitAMsTl9updWMT1/u6naYKAxJPGbZAY244EfPIQ9Ex2moF3Ux5k93oNeLAQgCrjTCOIr+uAQGgDnU5PND/mtgioeMUoKdzzg8Pnc1G0yuyDs3XQOBBIrojv9xJ81RCIRTCJ4PO1LHYRfGgFFrr5LfJl7uDngWDm7vaAVAX535YUrcyUyPJgL4cK+B/OUe0JoII2Zop03Qdm06pZ0D/mRQAAAABJRU5ErkJggg==";
        private static string Icon_2_24 = "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAESSURBVEhLtZRRDsIgDIbBeDD3qomH2Z7V6QF2F0181pshPyvIGAwY7EtIgW0t/UvHWSXatu2luY2rPzuym5GdgRBC2dP1dZDmoxaMNe/H+dt1nRiGYeIzKwM4l04gBdDOgT034P01Es10DsE5Z3ua53An28hhJCKLYo8aEsEaRLTupdZaKkXoFnmBc3wAe7w8hT3o2eSUIfDuUg2StQ6BGswCIKqD0Vdiz9eBAFoG0lVh7fepEgFunxgp6TWaBlY3jrufCqdTBvW2OxNBqNHSeyGWrtv6OaisEcAOgk0Md38ts1uEOtQCB43+i1SaBZgaeIpZLA9YykD/1MqoVUwfSTUoZdMAuJHRRisFGdQpphfGfkQwpkW09FEmAAAAAElFTkSuQmCC";
        private static string Icon_3_24 = "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEZSURBVEhLtZRBDsIgEEXBeDC71cTDtGu1eoDeRRPXejPk0wEpZVog9CXNUBwH+H+oFJVo27bX4Ta+/dlR3IzsEyilTDxdXwcdPuZFiOb9OH+7rlPDMExqZp0AxXURSAFsceCPHcgvkWimM4eUUuxpnMOdYqMfJxFFmD1qSLAerGjda62tVAaui6KgOP6AeLw8lf/Qb5NdciB3yYNkrTngwWwBrBrg9NX44zKwAMnQk66GYD5JIiDtjtcujs3DnBkksku9ONCTsG2aBO4BzJy0HActgtykfJzaN7mumRqzIRjmmwlKzIzhnyDW82bOmluKtLv0P7MomtstHEs3OatbWMiDKrsNCbtoEzZdAG3qTN4KnKCOmVGE+AH6MZ3XRLSL2wAAAABJRU5ErkJggg==";

        private static string Icon_0_32 = "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAE8SURBVFhH7ZVdDoIwEIQpx9NE7wLPKugz3EUTvV7t1K2B0nZLSsVEv2TDT8Hdnc6iKDIipSzqum7U6el1Z0pJx8VAUhOENzlIVmCQyIlSQD/Q9/0kF95NUoBLHkOyAlVVBffYkEUBgk2eFaWARNDlCHTIrS8+BT6QzA7AesA86INzuVn3wRaQYjLAvR8sIKYDg6+AEPj9GAV0AV3XOZ8NbQEHCog2oRDCGal8bAp8jArYHK6NCkkB84CWjkEgp4k5vDWkhLZb2/t512CfAy6fl9GixJhQ1a5RifnMRinkQ6ADOHx7vDk7UQqIkAIp2FPg6iSpuxh0AarD5nHZwwPDhC3uYY2u84AtCBmJW09htAVzx2cpVv8Q6SnACSbB9WnNJb8hRoG8k2BM9rMe+BfwPWO4FlAg+x+On6J4AnMSxsdaSfTCAAAAAElFTkSuQmCC";
        private static string Icon_1_32 = "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAE5SURBVFhH7ZXdDoIwDIWZj6eJvgtcq6DX8C6a6OvNHVwNwtYOxgKJfknDz2BtT1tQWUK01llRFKU5Pb/vDNnY42zAKZnF6xxEK9Bx5MQo0D7QNM3AF96NUkByHkK0AnmeszUmkihgEZ0nxSigYfbyC2QorY9SYHu8lca0NUgPKntkgbO+AbEH6MHd6e6qdfW47Et0uq/GNAU+RAXshwS4as3PuGpjYhViFaAM6rpWRgFnJkYB5VNAAvuzCtgMCFcmQfXnCGpClOF5PaAUXYcV7nVKlAZujIC0ziGWYAzYjGwMYuNQdr4mm5o9ocwGrvkewAQQ9L4PBBCUwZQxk2jLhQC4IKT1GGZtwqmsJ4Cx4zMXiyvwmQL8cHrf/pZUDUiEKBD9w2GhMfvZHvgHsJ4xXAookHbMWLLsBRYHxRTkiDehAAAAAElFTkSuQmCC";
        private static string Icon_2_32 = "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFDSURBVFhH7ZXdDoIwDIU3H08TfRe4VkGv4V000debO7iaKVsLbEQS/ZIFGT9tT09FqxkxxqiyLCv78/jc6bNyx2wgKC1HNDhIVsALpDaHq19tfTttK1KgbdteLDybpAATHByx1zQN9qMkJaC1ph6DkNSs/CCHB8QgHDlNWLujT2jvjVEJrPeXyi7jFklfow338w7nfkDfhK/J8BcQp4BuDJgMUBATczmuudMgogIpJoNJLWwbWAWoAjtK2ioQrMQqoGMKSOD9rAKuAmKSySQGmRBtCJkMe16L5qEoCoPlTntI1znEFowBL6M1BtE4VF3MZFOrJ7R9QWi+ezAJDHo+BhIYVMGUMZPo2oUEuCSk6ylkNeFUlpPA2PHJxdcVeE0BPjgf//0dcxmQGKJA8geHhcbsZz3wT2A5Y/gtoMC8Y8ai1AN9QceEVyon8QAAAABJRU5ErkJggg==";
        private static string Icon_3_32 = "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFISURBVFhH7ZVhjoIwEIVbj7eb6F3g9y6gv+Eua+Jer/bhDCnSdqil0ez6JQ1QkGnfvIdaFcQYo+q6bu1pc5tZsqPjZqAoDyJYHGQr4BRSn99nd7fd5bhvWYFhGBa18NssBSLFQYO5vu8xHyRrAVpr7jHwSR2VH2zhAbFIjC1N2NHRxTc3I2kBH18/rR2GBkvfoQ2/pwOu3YKuCadkuAOIKeAHPSYDXMSEXI57dOlFVCDHZDCpJdqGqAK8AxslbRXw7sQqoEMKSOD9UQVoB8xDJpNYZUK0wWcyzDktKkNVVQaDLhdI92MsWhCKGR2j4GU8UpiaTAWTYgYe3T2zsy9oadXJMSOyjKixg1Ixk7j3QJGYSYwL+LMxk5i1IDU+W7HqS1iSMQU4QRLuvv0jpeRn1ihQNglssn/rgfcCXieGzwIKFP/DCaPUFcCT56f94F9BAAAAAElFTkSuQmCC";

        public static Page GetIcon(double scaling)
        {
            return GetIcon(scaling, Icon16Base64, Icon24Base64, Icon32Base64);
        }

        private static Page GetIcon(double scaling, string low, string medium, string high)
        {
            if (scaling <= 1)
            {
                return GetIcon(low);
            }
            else if (scaling <= 1.5)
            {
                return GetIcon(medium);
            }
            else
            {
                return GetIcon(high);
            }
        }

        private static Page GetIcon(string byteImage)
        {
            byte[] bytes;

            bytes = Convert.FromBase64String(byteImage);

            IntPtr imagePtr = Marshal.AllocHGlobal(bytes.Length);
            Marshal.Copy(bytes, 0, imagePtr, bytes.Length);

            RasterImage icon;

            try
            {
                icon = new VectSharp.MuPDFUtils.RasterImageStream(imagePtr, bytes.Length, MuPDFCore.InputFileTypes.PNG);
            }
            catch (Exception ex)
            {
                throw ex.InnerException;
            }
            finally
            {
                Marshal.FreeHGlobal(imagePtr);
            }

            Page pag = new Page(16, 16);
            pag.Graphics.DrawRasterImage(0, 0, 16, 16, icon);

            return pag;
        }

        public static List<bool> IsAvailable(TreeNode selection, MainWindow window, InstanceStateData data)
        {
            bool canPolytomiseSelectedNode = selection != null && selection.Children.Count > 1 && selection.Parent != null;
            bool canPolytomiseAllDescendants = false;
            bool canPolytomiseDirectDescendants = false;

            if (selection != null)
            {
                foreach (TreeNode node in selection.Children)
                {
                    if (node != selection && node.Children.Count > 1)
                    {
                        canPolytomiseDirectDescendants = true;
                        break;
                    }
                }

                if (!canPolytomiseDirectDescendants)
                {
                    foreach (TreeNode node in selection.GetChildrenRecursiveLazy())
                    {
                        if (node != selection && node.Children.Count > 1)
                        {
                            canPolytomiseAllDescendants = true;
                            break;
                        }
                    }
                }
                else
                {
                    canPolytomiseAllDescendants = true;
                }
            }

            return new List<bool>()
            {
                canPolytomiseSelectedNode || canPolytomiseAllDescendants || canPolytomiseDirectDescendants,
                canPolytomiseSelectedNode,
                canPolytomiseDirectDescendants,
                canPolytomiseDirectDescendants,
                canPolytomiseAllDescendants
            };
        }

        public static void PerformAction(int actionIndex, TreeNode selection, MainWindow window, InstanceStateData data)
        {
            if (actionIndex == -1)
            {
                bool canPolytomiseSelectedNode = selection != null && selection.Children.Count > 1 && selection.Parent != null;
                bool canPolytomiseDirectDescendants = false;

                if (selection != null)
                {
                    foreach (TreeNode node in selection.Children)
                    {
                        if (node != selection && node.Children.Count > 1)
                        {
                            canPolytomiseDirectDescendants = true;
                            break;
                        }
                    }
                }

                if (!canPolytomiseDirectDescendants && canPolytomiseSelectedNode)
                {
                    actionIndex = 0;
                }
                else
                {
                    actionIndex = 2;
                }
            }

            List<string> nodeNames = selection.GetNodeNames();

            if (nodeNames.Count == 0 || !selection.IsLastCommonAncestor(nodeNames))
            {
                if (InstanceStateData.IsUIAvailable)
                {
                    MessageBox box = new MessageBox("Attention!", "The requested node cannot be uniquely identified! Please, make sure that it either has a Name or enough of its children have Names.");
                    box.ShowDialog2(window);
                }
                else if (InstanceStateData.IsInteractive)
                {
                    Console.WriteLine();
                    Console.WriteLine("Attention! The requested node cannot be uniquely identified! Please, make sure that it either has a Name or enough of its children have Names.");
                    Console.WriteLine();
                }
                return;
            }

            if (InstanceStateData.IsUIAvailable)
            {
                window.PushUndoFrame(UndoFrameLevel.FurtherTransformationModule, window.FurtherTransformations.Count);
            }

            if (actionIndex == 0)
            {
                FurtherTransformationModule module = Modules.GetModule(Modules.FurtherTransformationModules, "19d9a555-07e6-4dac-afc1-d5ffcef35f76");
                Action<Dictionary<string, object>> changeParameter = data.AddFurtherTransformationModule(module);
                changeParameter(new Dictionary<string, object>() { { "Node:", nodeNames.ToArray() } });

                if (InstanceStateData.IsUIAvailable)
                {
                    Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(async () =>
                    {
                        await window.UpdateFurtherTransformations(window.FurtherTransformations.Count - 1);
                        window.SetSelection(window.TransformedTree.GetLastCommonAncestor(new string[] { nodeNames[0], nodeNames[^1] }));
                    });
                }
            }
            else if (actionIndex == 3)
            {
                FurtherTransformationModule module = Modules.GetModule(Modules.FurtherTransformationModules, "19d9a555-07e6-4dac-afc1-d5ffcef35f76");
                Action<Dictionary<string, object>> changeParameter = data.AddFurtherTransformationModule(module);
                changeParameter(new Dictionary<string, object>() { { "Node:", nodeNames.ToArray() }, { "Apply recursively to all children", true } });

                if (InstanceStateData.IsUIAvailable)
                {
                    Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(async () =>
                    {
                        await window.UpdateFurtherTransformations(window.FurtherTransformations.Count - 1);
                        window.SetSelection(window.TransformedTree.GetLastCommonAncestor(new string[] { nodeNames[0], nodeNames[^1] }));
                    });
                }
            }
            else if (actionIndex == 1)
            {
                if (InstanceStateData.IsUIAvailable)
                {
                    Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(async () =>
                    {

                        foreach (TreeNode node in selection.Children)
                        {
                            if (node.Children.Count > 1)
                            {
                                List<string> currNodeNames = node.GetNodeNames();

                                if (currNodeNames.Count == 0 || !node.IsLastCommonAncestor(currNodeNames))
                                {
                                    MessageBox box = new MessageBox("Attention!", "The requested node cannot be uniquely identified! Please, make sure that it either has a Name or enough of its children have Names.");
                                    await box.ShowDialog2(window);
                                    return;
                                }

                                FurtherTransformationModule module = Modules.GetModule(Modules.FurtherTransformationModules, "19d9a555-07e6-4dac-afc1-d5ffcef35f76");
                                Action<Dictionary<string, object>> changeParameter = data.AddFurtherTransformationModule(module);
                                changeParameter(new Dictionary<string, object>() { { "Node:", currNodeNames.ToArray() } });

                                await window.UpdateFurtherTransformations(window.FurtherTransformations.Count - 1);
                            }
                        }

                        window.SetSelection(window.TransformedTree.GetLastCommonAncestor(new string[] { nodeNames[0], nodeNames[^1] }));
                    });
                }
                else
                {
                    foreach (TreeNode node in selection.Children)
                    {
                        if (node.Children.Count > 1)
                        {
                            List<string> currNodeNames = node.GetNodeNames();

                            if (currNodeNames.Count == 0 || !node.IsLastCommonAncestor(currNodeNames))
                            {
                                if (InstanceStateData.IsInteractive)
                                {
                                    Console.WriteLine();
                                    Console.WriteLine("Attention! The requested node cannot be uniquely identified! Please, make sure that it either has a Name or enough of its children have Names.");
                                    Console.WriteLine();
                                }

                                return;
                            }

                            FurtherTransformationModule module = Modules.GetModule(Modules.FurtherTransformationModules, "19d9a555-07e6-4dac-afc1-d5ffcef35f76");
                            Action<Dictionary<string, object>> changeParameter = data.AddFurtherTransformationModule(module);
                            changeParameter(new Dictionary<string, object>() { { "Node:", currNodeNames.ToArray() } });
                        }
                    }
                }
            }
            else if (actionIndex == 2)
            {
                if (InstanceStateData.IsUIAvailable)
                {
                    Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(async () =>
                    {

                        foreach (TreeNode node in selection.Children)
                        {
                            if (node.Children.Count > 1)
                            {
                                List<string> currNodeNames = node.GetNodeNames();

                                if (currNodeNames.Count == 0 || !node.IsLastCommonAncestor(currNodeNames))
                                {
                                    MessageBox box = new MessageBox("Attention!", "The requested node cannot be uniquely identified! Please, make sure that it either has a Name or enough of its children have Names.");
                                    await box.ShowDialog2(window);
                                    return;
                                }

                                FurtherTransformationModule module = Modules.GetModule(Modules.FurtherTransformationModules, "19d9a555-07e6-4dac-afc1-d5ffcef35f76");
                                Action<Dictionary<string, object>> changeParameter = data.AddFurtherTransformationModule(module);
                                changeParameter(new Dictionary<string, object>() { { "Node:", currNodeNames.ToArray() }, { "Apply recursively to all children", true } });

                                await window.UpdateFurtherTransformations(window.FurtherTransformations.Count - 1);
                            }
                        }

                        window.SetSelection(window.TransformedTree.GetLastCommonAncestor(new string[] { nodeNames[0], nodeNames[^1] }));
                    });
                }
                else
                {
                    foreach (TreeNode node in selection.Children)
                    {
                        if (node.Children.Count > 1)
                        {
                            List<string> currNodeNames = node.GetNodeNames();

                            if (currNodeNames.Count == 0 || !node.IsLastCommonAncestor(currNodeNames))
                            {
                                if (InstanceStateData.IsInteractive)
                                {
                                    Console.WriteLine();
                                    Console.WriteLine("Attention! The requested node cannot be uniquely identified! Please, make sure that it either has a Name or enough of its children have Names.");
                                    Console.WriteLine();
                                }

                                return;
                            }

                            FurtherTransformationModule module = Modules.GetModule(Modules.FurtherTransformationModules, "19d9a555-07e6-4dac-afc1-d5ffcef35f76");
                            Action<Dictionary<string, object>> changeParameter = data.AddFurtherTransformationModule(module);
                            changeParameter(new Dictionary<string, object>() { { "Node:", currNodeNames.ToArray() }, { "Apply recursively to all children", true } });
                        }
                    }
                }
            }
        }
    }
}